package dao

import (
	"fmt"
	"strconv"
	"time"

	"github.com/go-xorm/xorm"

	"im/common"
	"im/errcode"
	"im/model"
	"im/requests"
	"im/service/cache"
	"im/service/orm"
)

type UsersDao struct {
	db *xorm.Engine
}

func NewUsersDao() *UsersDao {
	return &UsersDao{db: orm.GetDB()}
}

// 获取用户上线信息的cache_key
func onlineKey(appId uint, userId int64) string {
	return fmt.Sprintf("%d_%d", appId, userId)
}

// 根据融云key获取用户信息
func (u *UsersDao) GetInfoByToken(tk string) (model.Users, error) {
	var uu model.Users
	exist, err := u.db.Where("token=?", tk).Get(&uu)
	if err != nil {
		return uu, errcode.NewError(errcode.DaoFailed, err)
	}
	if !exist {
		return uu, errcode.NewError(errcode.UnauthorizedOperation, err)
	}
	return uu, nil
}

func (u *UsersDao) IsOnline(appId uint, userId int64) bool {
	if cache.Init().HGet(strconv.Itoa(cache.USERS_COMM_MAP), onlineKey(appId, userId)).String() == "" {
		return false
	}
	return true
}

// 用户上线
func (u *UsersDao) Online(appId uint, userId int64, cid string) error {
	return cache.Init().HSet(strconv.Itoa(cache.USERS_COMM_MAP), onlineKey(appId, userId), cid).Err()
}

// 用户下线
func (u *UsersDao) OffLine(appId uint, userId int64) error {
	m := &model.Users{}
	m.LastOnlineAt = time.Now()
	_, err := u.db.Cols("last_online_at").Where("apps_id=?", appId).Where("id=?", userId).Update(m)
	if err != nil {
		return err
	}
	return cache.Init().HDel(strconv.Itoa(cache.USERS_COMM_MAP), onlineKey(appId, userId)).Err()
}

// 用户信息获取
func (u *UsersDao) Info(userId int64) *model.Users {
	user := new(model.Users)
	find, err := u.db.Where("id=?", userId).Get(user)
	if err != nil {
		panic(err)
	}
	if !find {
		return nil
	}
	return user
}

func (u *UsersDao) UpdateById(userId int64, data requests.UsersPutParams) error {
	uu := model.Users{
		UsersVisually: model.UsersVisually{
			UserModifiable: model.UserModifiable{
				Nickname:   data.Nickname,
				Avatar:     data.Avatar,
				PushToken:  data.PushToken,
				CoverImage: data.CoverImage,
			}},
		Status: data.Status,
	}
	_, err := u.db.Where("id=?", userId).Update(uu)
	return err
}
func (u *UsersDao) GetInfoMapByIds(userId ...int64) (map[int64]model.Users, error) {
	var (
		ms    = []model.Users{}
		msMap = map[int64]model.Users{}
		err   error
	)
	err = u.db.Cols("id", "nickname", "avatar").In("id", userId).Find(&ms)
	if err != nil {
		return msMap, errcode.NewError(errcode.DaoFailed, err)
	}
	for _, row := range ms {
		msMap[row.Id] = row
	}
	return msMap, nil
}
func (u *UsersDao) GetListByUserIds(userIds []int64) ([]model.UsersVisually, error) {
	var ms []model.Users
	var mvs []model.UsersVisually
	err := u.db.In("id", common.ToInterfaceSlice(userIds)...).Find(&ms)
	if err != nil {
		return mvs, errcode.NewError(errcode.DaoFailed, err)
	}
	mvs = []model.UsersVisually{}
	for _, m := range ms {
		mvs = append(mvs, m.UsersVisually)
	}
	return mvs, nil
}

func (u *UsersDao) Incr(userId int64, field string) error {
	_, err := u.db.Where("id=?", userId).Incr(field, 1).Update(&model.Users{})
	if err != nil {
		return errcode.NewError(errcode.DaoFailed, err)
	}
	return nil
}
func (u *UsersDao) Decr(userId int64, field string) error {
	_, err := u.db.Where("id=?", userId).Where(field+">0").Decr(field, 1).Update(&model.Users{})
	if err != nil {
		return errcode.NewError(errcode.DaoFailed, err)
	}
	return nil
}
